import { cubic, labelCfg } from '@/graph/style/edge-style';
import { uuid } from '@/utils';

export default (G6) => {

  G6.registerBehavior('drag-shadow-node', {

    getDefaultCfg() {
      return {
        distance: [],
        dragTarget: null,
        dragStartNode: {},
        isGragging: false,
        dragTarget: 'node',
        sourceAnchorIndex: 0,
      }
    },
    shouldBegin(e, self) { return true },
    // shouldUpdate(e, self) { return true },
    // shouldEnd(e, self) { return true },

    getEvents() {
      return {
        'node:mousedown': 'mousedown',
        'node:dragstart': 'dragStart',
        'node:drag': 'drag',
        'node:dragend': 'dragEnd',
        'node:mouseup': 'mouseup',
        'node:drop': 'drop',
      };
    },

    dragStart(e) {
      if (!this.shouldBegin(e)) return;
      const group = e.item.getContainer();
      const { x, y } = e;
      this.isGragging = true;
      this.origin = { x, y };

      if (e.target.get('isAnchor')) {

        this.sourceAnchorIndex = e.target.get('index');
        return

      };

      e.item.toFront();
      group.getFirst().cfg.xShapeNode && (this.dragTarget = 'node');
      const item = group.get('item');
      const model = item.get('model');
      const { radius } = item.get('originStyle');
      const currentShape = item.get('currentShape');
      const { width, height, centerX, centerY } = item.getBBox();
      const shapes = item.get('shapeFactory')[currentShape];

      let { shapeType } = shapes || {};
      let attrs = { fillOpacity: 0.1, fill: '#1890FF', stroke: '#1890FF', cursor: 'move', lineDash: [4, 4], width, height, x: model.x, y: model.y };

      switch (shapeType) {
        case 'circle':
          this.distance = [e.x - centerX, e.y - centerY];
          attrs = { ...attrs, r: width / 2 };
          break;
        case 'rect':
          this.distance = [e.x - centerX + width / 2, e.y - centerY + height / 2];
          attrs = { ...attrs, x: -width / 2, y: -height / 2, r: width / 2 };
          if (radius) attrs.radius = radius;
          break;
        case 'ellipse':
          this.distance = [e.x - centerX, e.y - centerY];
          attrs = { ...attrs, rx: width / 2, ry: height / 2 };
          break;
        case 'path':
          this.distance = [e.x - centerX, e.y - centerY];
          attrs.path = item.get('keyShape').attrs.path;
          attrs.width = width;
          attrs.height = height;
          break;
        default:
          this.distance = [e.x - centerX, e.y - centerY];
          attrs = { ...attrs, r: width / 2 };
          shapeType = 'circle';
          break;
      }

      const shadowNode = group.addShape(shapeType, {
        name: 'shadow-node',
        attrs,
      });

      shadowNode.toFront();
    },

    drag(e) {
      if (!this.shouldBegin(e)) return;
      if (!this.isGragging) return;
      const group = e.item.getContainer();
      if (this.dragTarget !== 'node' && group.getFirst().cfg.xShapeNode) return;

      const item = group.get('item');
      const pathAttrs = group.getFirst();
      const { width, height, centerX, centerY } = item.getBBox();
      const shape = group.find((shape) => shape.get('name') === 'shadow-node');
      const shadowNode = pathAttrs.cfg.xShapeNode ? shape : null;

      const shapes = item.get('shapeFactory')[item.get('currentShape')];
      const { shapeType } = shapes || {};


      if (shapeType === 'path') {
        const { type, direction } = pathAttrs.get('attrs');
        const dx = e.x - centerX - this.distance[0];
        const dy = e.y - centerY - this.distance[1];
        const path = [['Z']];

        switch (type) {
          case 'diamond-node':
            path.unshift(
              ['M', dx, dy - height / 2], // 上顶点
              ['L', dx + width / 2, dy], // 右侧顶点
              ['L', dx, dy + height / 2], // 下顶点
              ['L', dx - width / 2, dy], // 左侧顶点
            );
            break;
          case 'triangle-node':
            //顶点 右侧顶点、左侧顶点
            if (direction === 'down') {
              path.unshift(['M', dx, dy + height], ['L', dx + width / 2, dy], ['L', dx - width / 2, dy]);
            } else if (direction === 'left') {
              path.unshift(['M', dx - width, dy], ['L', dx, dy + height / 2], ['L', dx, dy - height / 2]);
            } else if (direction === 'right') {
              path.unshift(['M', dx + width, dy], ['L', dx, dy + height / 2], ['L', dx, dy - height / 2]);
            } else {
              path.unshift(['M', dx, dy - height], ['L', dx + width / 2, dy], ['L', dx - width / 2, dy]); // top
            }
            break;
        }

        shadowNode.attr({ path });

      } else {
        shadowNode.attr({ x: e.x - centerX - this.distance[0], y: e.y - centerY - this.distance[1] });
      }

      shadowNode.toFront();
    },

    dragEnd(e) {
      if (!this.shouldBegin(e)) return;
      const group = e.item.getContainer();
      this.isGragging = false;

      if (this.dragTarget === 'anchor') {
        const nodes = this.graph.findAll('node', node => node);
        nodes.forEach(node => node.clearStates('active_anchor'));
        return;
      }

      const { graph } = this;
      const model = e.item.getModel();
      const shape = group.find((shape) => shape.get('name') === 'shadow-node');
      const shadowNode = group.getFirst().cfg.xShapeNode ? shape : null;

      if (!shadowNode) return;

      const x = e.x - this.origin.x + model.x;
      const y = e.y - this.origin.y + model.y;
      const pos = { x, y };

      shadowNode.remove();
      graph.updateItem(e.item, pos);

    },

    mousedown(e) {
      if (!this.shouldBegin(e)) return;
      this.clearSelected(e);
      if (!e.target.cfg.isAnchor) return;

      e.target.get('isAnchor') && (this.dragTarget = 'anchor');// 拖拽锚点
      this.dragStartNode = { ...e.item._cfg, anchorIndex: e.target.cfg.index };
      const nodes = this.graph.findAll('node', node => node);

      nodes.forEach(node => {
        node.setState('active_anchor', true);
      });
    },

    mouseup(e) {
      if (!this.shouldBegin(e)) return;
      if (this.dragTarget === 'anchor') {
        const nodes = this.graph.findAll('node', node => node);
        nodes.forEach(node => node.clearStates('active_anchor'));
      }
    },

    clearSelected(e) { },

    drop(e) {
      if (!this.shouldBegin(e)) return;// e.target 当前拖拽节点 | e.item 当前释放节点
      const { dragStartNode, sourceAnchorIndex } = this;
      const { isAnchor, nodeId } = e.target.cfg;
      if (!isAnchor && !dragStartNode.id && dragStartNode.id === nodeId) return;

      const sourceNode = dragStartNode.group.get('item');
      const { singleEdge } = sourceNode.getModel(); // 同个source和同个target只能有1条线
      const targetAnchorIndex = e.target.get('index');
      const edges = sourceNode.getOutEdges();

      const hasLinked = edges.find(edge => {

        const source_id = edge.get('source').get('id');
        const target_id = edge.get('target').get('id');
        const sourceIndex = edge.get('sourceAnchorIndex');
        const targetIndex = edge.get('targetAnchorIndex');

        if (

          singleEdge &&
          target_id === nodeId ||
          target_id === nodeId &&
          source_id === sourceNode.get('id') &&
          sourceIndex === sourceAnchorIndex &&
          targetIndex === targetAnchorIndex

        ) return true;

      });

      if (hasLinked) return;
      if (sourceNode.get('id') === nodeId) return;
      if (e.target.cfg.index === undefined) return;

      // 获取起点和终端的label
      this.graph.addItem('edge', {
        id: `edge-${uuid()}`,
        type: 'cubic-edge',
        label: `${sourceNode.get('id')}-${nodeId}`,
        style: cubic,
        animate: true,
        source: sourceNode,
        target: e.item.getContainer().get('item'),
        sourceAnchor: dragStartNode.anchorIndex,
        targetAnchor: e.target.cfg.index,
      }, true);

    },

  });

}